package controllers;

import static play.data.Form.form;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import models.Chapitre;
import models.Choix;
import models.Matiere;
import models.NiveauQuestion;
import models.Qcm;
import models.QcmNiveauquestion;
import models.Question;
import models.Statut;
import models.Theme;
import models.Utilisateur;

import play.Logger;
import play.data.DynamicForm;
import play.data.Form;
import play.mvc.Controller;
import play.mvc.Http.Session;
import play.mvc.Result;

import views.html.CreateQCM.*;

import views.html.pageErreurConnexion;

public abstract class CreateQCM extends Controller {
	public static Result step(final int step) {

		// Vérification sur le Statut du Utilisateur afficher que si Statut=Expert
		final long idUtilisateur = Long.parseLong(session().get("id"));
		final Utilisateur temp = Utilisateur.findById(idUtilisateur);
		Qcm qcm = null;
		if (temp.getStatut().equals(Statut.Etudiant)) {
			return ok(pageErreurConnexion.render());
		}

		try {
			qcm = toQcm(session());
		} catch (ParseException e) {
			Logger.debug(e.toString());
		}
		final Form<Qcm> qcmForm = form(Qcm.class).fill(qcm);

		// Creation du formulaire pour récupérer les champs
		switch (step) {

		// initialisation libelle date ouverture et cloture
		case 1:
			// Créer le qcm en fonction de la session()

			String dateOuverture = null;
			String dateFermeture = null;
			final GregorianCalendar cal = new GregorianCalendar();
			final GregorianCalendar cal2 = new GregorianCalendar();
			try {
				if (qcmForm.field("dateOuverture").value() != null) {
					cal.setTime(qcm.getDateOuverture());
					dateOuverture = Utile.dateToString(cal);
				}

				if (qcmForm.field("dateCloture").value() != null) {
					cal2.setTime(qcm.getDateCloture());
					dateFermeture = Utile.dateToString(cal2);
				}
			} catch (ParseException e) {
				Logger.debug(e.toString());
			}

			return ok(initiateQcm.render(qcmForm, dateOuverture, dateFermeture));

			// liste des questions
		case 2:
			final List<Theme> allThemes = Theme.findAll();
			return ok(associerQuestionQcm.render(qcmForm, qcm, allThemes));

			// Notation
		case 3:
			return ok(notation.render(qcmForm, qcm, session().get("ppf"),
					session().get("pnf"), session().get("ppm"),
					session().get("pnm"), session().get("ppd"),
					session().get("pnd"), session().get("ppb"),
					session().get("pnb")));

		case 4:
			return ok(recupilatif.render(qcm));

		case 5:
			final StringBuilder s = new StringBuilder();
			s.append("QCM créé. \n Conservez bien la clé : "
					+ session().get("cleQcm") + ".");
			s.append("\n");
			s.append("Vous pouvez le consulter en allant dans l'onglet lister QCM.");
			return Application.redirectionAccueil(s.toString());

		default:
			return forbidden();
		}

	}

	/**
	 * Envoie de chaque partie de la creation du QCM
	 */
	public static Result submit(final int step) {
		final DynamicForm filledForm = form().bindFromRequest();

		if (step == 1) {
			toMap1(filledForm);
			Logger.debug("\n" + "Step 1_qcmForm :" + session().toString()
					+ "\n");
			return redirect(routes.CreateQCM.step(2));
		}
		if (step == 2) {
			final StringBuilder listeQuestion = getUtilisateurChoseQuestion();
			if ("retour".equals(filledForm.field("action").value())) {
				return redirect(routes.CreateQCM.step(1));
			} else {
				toMap2(listeQuestion);
				Logger.debug("\n" + "Step 2_qcmForm :" + session().toString()
						+ "\n");
				return redirect(routes.CreateQCM.step(3));
			}
		}
		if (step == 3) {
			if ("retour".equals(filledForm.field("action").value())) {
				return redirect(routes.CreateQCM.step(2));
			} else {
				// Update de la session grâce aux informations de notation
				toMap3(filledForm);
				Logger.debug("\n" + "Step 1_qcmForm :" + session().toString()
						+ "\n");
				return redirect(routes.CreateQCM.step(4));
			}
		} else {
			if ("retour".equals(filledForm.field("action").value())) {
				return redirect(routes.CreateQCM.step(3));
			} else {
				Logger.debug("\n" + "Step 1_qcmForm :" + session().toString()
						+ "\n");
				Qcm newQcm = null;
				try {
					newQcm = toQcm(session());
				} catch (ParseException e) {
					Logger.debug(e.toString());
				}

				// Récupération de la date d'aujourd'hui
				final GregorianCalendar today = new GregorianCalendar();
				newQcm.setDateCreation(today.getTime());

				// Récupération de l'objet Expert
				final long idUtilisateur = Long.parseLong(session().get("id"));
				final Utilisateur expert = Utilisateur.findById(idUtilisateur);
				newQcm.setUtilisateur(expert);

				// Géneration de la clé
				newQcm.setCleAuthentification(Utile.generateCle());

				// Sauvegarde + effacer la session + récupération de l'id
				newQcm.save();

				// Clear the session
				session().clear();
				session().put("id", newQcm.getUtilisateur().getIdUtilisateur().toString());
				session().put("cleQcm", newQcm.getCleAuthentification());
				session()
						.put("statut", newQcm.getUtilisateur().getStatut().toString());
				Logger.debug("Création QCM : Id = " + newQcm.getIdQcm()
						+ " Libelle = " + newQcm.getLibelle() + " par user "
						+ session().get("id"));
				return redirect(routes.CreateQCM.step(5));
			}
		}
	}

	private static void toMap1(final Form<?> qcm) {
		final Map<String, String> map = new HashMap<String, String>();
		map.put("libelle", qcm.field("libelle").valueOr(""));
		map.put("dateOuverture", qcm.field("dateOuverture").valueOr(""));
		map.put("dateCloture", qcm.field("dateCloture").valueOr(""));
		session().putAll(map);
	}

	private static void toMap2(final StringBuilder liste) {
		final Map<String, String> map = new HashMap<String, String>();
		final String listeIdQuestion = liste.toString();
		map.put("listeQuestions", listeIdQuestion);
		map.put("ppf", "1");
		map.put("pnf", "0");
		map.put("ppm", "1");
		map.put("pnm", "0");
		map.put("ppd", "1");
		map.put("pnd", "0");
		map.put("ppb", "1");
		map.put("pnb", "0");
		session().putAll(map);
	}

	private static void toMap3(final Form<?> qcm) {
		final Map<String, String> map = new HashMap<String, String>();
		map.put("ppf", qcm.field("ppf").valueOr("1"));
		map.put("pnf", qcm.field("pnf").valueOr("0"));
		map.put("ppm", qcm.field("ppm").valueOr("1"));
		map.put("pnm", qcm.field("pnm").valueOr("0"));
		map.put("ppd", qcm.field("ppd").valueOr("1"));
		map.put("pnd", qcm.field("pnd").valueOr("0"));
		map.put("ppb", qcm.field("ppb").valueOr("1"));
		map.put("pnb", qcm.field("pnb").valueOr("0"));
		session().putAll(map);
	}

	/**
	 * Creer l'objet final grâce à la session
	 * 
	 * @param session
	 * @return
	 */

	private static Qcm toQcm(final Session session) throws ParseException {
		Qcm qcm = new Qcm();

		final List<Question> listeQuestions = new ArrayList<Question>();

		if (session.get("dateCloture") != null) {
			qcm.setDateCloture(Utile.stringToDate(session.get("dateCloture")));
		}
		if (session.get("dateOuverture") != null) {
			qcm.setDateOuverture(Utile.stringToDate(session
					.get("dateOuverture")));
		}
		qcm.setLibelle(session.get("libelle"));
		qcm.setListeQuestions(listeQuestions);

		if (session.get("listeQuestions") != null
				&& session.get("listeQuestions").length() > 0) {
			String listeIdQuestion = session.get("listeQuestions");
			listeIdQuestion = listeIdQuestion.replaceAll("\\s", "");
			final String[] listeId = listeIdQuestion.split("#");
			for (int i = 0; i < listeId.length; i++) {
				final long idQuestion = Long.parseLong(listeId[i]);
				listeQuestions.add(Question.findById(idQuestion));
			}
			Set<Question> mySet = new HashSet<Question>(listeQuestions);
			List<Question> listeQuestions2 = new ArrayList<Question>(mySet); 
			qcm.setListeQuestions(listeQuestions2);
		}
		if (session.get("ppf") != null && session.get("pnf") != null
				&& session.get("ppm") != null && session.get("pnm") != null
				&& session.get("ppd") != null && session.get("pnd") != null
				&& session.get("ppb") != null && session.get("pnb") != null
				&& !session.get("ppf").isEmpty()
				&& !session.get("pnf").isEmpty()
				&& !session.get("ppm").isEmpty()
				&& !session.get("pnm").isEmpty()
				&& !session.get("ppd").isEmpty()
				&& !session.get("pnd").isEmpty()
				&& !session.get("ppb").isEmpty()
				&& !session.get("pnb").isEmpty()) {
			qcm = updateQcmNiveauQuestion(session, qcm);
		}
		return qcm;
	}

	/**
	 * Concatene la liste des questions choisies
	 * 
	 * @param s
	 * @return
	 */
	private static StringBuilder getUtilisateurChoseQuestion() {
		final Map<String, String[]> urlFormEncoded = request().body()
				.asFormUrlEncoded();
		final StringBuilder listQuestions = new StringBuilder();
		if (urlFormEncoded != null) {
			for (String key : urlFormEncoded.keySet()) {
				final String[] value = urlFormEncoded.get(key);
				// on selectionne liste de Question
				if (value.length > 1) {
					for (int i = 0; i < value.length; i++) {
						listQuestions.append(value[i] + "#");
					}
					listQuestions.deleteCharAt(listQuestions.length() - 1);
				}
			}
		}
		return listQuestions;
	}

	/**
	 * Enregistre la liste des question dans le qcm
	 * 
	 * @param session
	 * @param qcm
	 * @return qcm
	 * @throws ParseException
	 */
	private static Qcm updateQcmNiveauQuestion(final Session session,
			final Qcm qcm) throws ParseException {
		final QcmNiveauquestion tempFacile = new QcmNiveauquestion();
		final QcmNiveauquestion tempMedium = new QcmNiveauquestion();
		final QcmNiveauquestion tempDifficile = new QcmNiveauquestion();
		final QcmNiveauquestion tempBonus = new QcmNiveauquestion();
		final List<QcmNiveauquestion> listeNiveauQuestions = new ArrayList<QcmNiveauquestion>();

		tempFacile.setNiveauQuestion(NiveauQuestion.findById(1L));
		tempMedium.setNiveauQuestion(NiveauQuestion.findById(2L));
		tempDifficile.setNiveauQuestion(NiveauQuestion.findById(3L));
		tempBonus.setNiveauQuestion(NiveauQuestion.findById(4L));

		tempFacile.setPointNegatif(Double.parseDouble(session.get("pnf")));
		tempFacile.setPointPositif(Double.parseDouble(session.get("ppf")));
		tempMedium.setPointNegatif(Double.parseDouble(session.get("pnm")));
		tempMedium.setPointPositif(Double.parseDouble(session.get("ppm")));
		tempDifficile.setPointNegatif(Double.parseDouble(session.get("pnd")));
		tempDifficile.setPointPositif(Double.parseDouble(session.get("ppd")));
		tempBonus.setPointNegatif(Double.parseDouble(session.get("pnb")));
		tempBonus.setPointPositif(Double.parseDouble(session.get("ppb")));

		listeNiveauQuestions.add(tempFacile);
		listeNiveauQuestions.add(tempMedium);
		listeNiveauQuestions.add(tempDifficile);
		listeNiveauQuestions.add(tempBonus);

		qcm.setListeNiveauQuestions(listeNiveauQuestions);
		return qcm;
	}

	/**
	 * Retourne la liste des Matières suivant un thème
	 * 
	 * @param idtheme
	 * @return
	 */
	public static Result getMatiere(final int idtheme) {
		// Vérification sur le Statut du Utilisateur afficher que si Statut=Expert
		final long idUtilisateur = Long.parseLong(session().get("id"));
		final Utilisateur temp = Utilisateur.findById(idUtilisateur);

		if (temp.getStatut().equals(Statut.Etudiant)) {
			return ok(pageErreurConnexion.render());
		}
		Theme t = new Theme();
		final Long idL = (long) idtheme;
		t = Theme.findById(idL);
		final List<Matiere> allMatiere = t.getSesMatieres();
		final StringBuilder list = new StringBuilder();
		for (int i = 0; i < allMatiere.size(); i++) {
			final Matiere m = allMatiere.get(i);
			list.append(m.getIdMatiere() + "#" + m.getLibelleM() + ";");
		}
		list.deleteCharAt(list.length() - 1);
		return ok(listeMatiere.render(list.toString()));
	}

	/**
	 * Retourne la liste des Chapitre suivant une matière
	 * 
	 * @param idmatiere
	 * @return
	 */
	public static Result getChapitre(final int idmatiere) {
		// Vérification sur le Statut du Utilisateur afficher que si Statut=Expert
		final long idUtilisateur = Long.parseLong(session().get("id"));
		final Utilisateur temp = Utilisateur.findById(idUtilisateur);

		if (temp.getStatut().equals(Statut.Etudiant)) {
			return ok(pageErreurConnexion.render());
		}
		Matiere m = new Matiere();
		final Long idL = (long) idmatiere;
		m = Matiere.findById(idL);
		final List<Chapitre> allChapitre = m.getSesChapitres();
		final StringBuilder list = new StringBuilder();
		for (int i = 0; i < allChapitre.size(); i++) {
			final Chapitre c = allChapitre.get(i);
			list.append(c.getIdChapitre() + "#" + c.getLibelleC() + ";");
		}
		list.deleteCharAt(list.length() - 1);
		return ok(listeChapitre.render(list.toString()));
	}

	/**
	 * Retourne la liste des Question suivant le chapitre
	 * 
	 * @param idChapitre
	 * @return
	 */
	public static Result getQuestion(final int idChapitre) {
		// Vérification sur le Statut du Utilisateur afficher que si Statut=Expert
		final long idUtilisateur = Long.parseLong(session().get("id"));
		final Utilisateur temp = Utilisateur.findById(idUtilisateur);

		if (temp.getStatut().equals(Statut.Etudiant)) {
			return ok(pageErreurConnexion.render());
		}
		final Long idL = (long) idChapitre;
		Chapitre c = new Chapitre();
		c = Chapitre.findById(idL);
		final List<Question> allQuestion = c.getSesQuestions();
		final StringBuilder list = new StringBuilder();
		for (int i = 0; i < allQuestion.size(); i++) {
			final Question q = allQuestion.get(i);
			list.append(q.getIdQuestion() + "#" + q.getLibelleQuestion() + ";");
		}
		list.deleteCharAt(list.length() - 1);
		return ok(listeQuestion.render(list.toString()));
	}

	/**
	 * Retourne les commentaires de la question
	 * 
	 * @param idquestion
	 * @return
	 */
	public static Result getCommentaire(final int idquestion) {
		// Vérification sur le Statut du Utilisateur afficher que si Statut=Expert
		final long idUtilisateur = Long.parseLong(session().get("id"));
		final Utilisateur temp = Utilisateur.findById(idUtilisateur);

		if (temp.getStatut().equals(Statut.Etudiant)) {
			return ok(pageErreurConnexion.render());
		}

		final Long idL = (long) idquestion;
		Question q = new Question();
		q = Question.findById(idL);
		final StringBuilder list = new StringBuilder();
		list.append(q.getLibelleQuestion() + ";" + q.getCommentaire() + ";"
				+ q.getNiveauQuestion().getLibelleNiveau() + ";");
		final List<Choix> allChoix = q.getListeChoix();
		for (int i = 0; i < allChoix.size(); i++) {
			final Choix c = allChoix.get(i);
			list.append(c.getDescriptifChoix() + "#" + c.getEstVrai() + "#");
		}
		list.deleteCharAt(list.length() - 1);
		return ok(commentaireQuestion.render(list.toString()));
	}
}